﻿using Org.BouncyCastle.Asn1.X509;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace UIWindows.Tools.Helper
{
    public static class ConversionHelper
    {
        /// <summary>
        /// XCode实体专用复制
        /// </summary>
        /// <typeparam name="TSourc"></typeparam>
        /// <typeparam name="TTarget"></typeparam>
        /// <returns></returns>
        public static Action<TSourc, TTarget> CopyXCodeEntity<TSourc, TTarget>()
        {
            System.Linq.Expressions.ParameterExpression pe_Sourc = System.Linq.Expressions.Expression.Parameter(typeof(TSourc), "p");
            System.Linq.Expressions.ParameterExpression pe_Target = System.Linq.Expressions.Expression.Parameter(typeof(TSourc), "t");
            List<System.Linq.Expressions.BinaryExpression> binaryExpressions = new List<System.Linq.Expressions.BinaryExpression>();
            var propertie = typeof(TSourc).GetProperties();
            for (int i = 0; i < propertie.Length - 3; i++)
            {
                if (!propertie[i].CanWrite) continue;
                System.Linq.Expressions.MemberExpression property_Sourc = System.Linq.Expressions.Expression.Property(pe_Sourc, typeof(TSourc).GetProperty(propertie[i].Name));
                System.Linq.Expressions.MemberExpression property_Target = System.Linq.Expressions.Expression.Property(pe_Target, typeof(TSourc).GetProperty(propertie[i].Name));
                binaryExpressions.Add(System.Linq.Expressions.Expression.MakeBinary(ExpressionType.Assign, property_Target, property_Sourc));
            }
            System.Linq.Expressions.Expression<Action<TSourc, TTarget>> lambda = System.Linq.Expressions.Expression.Lambda<Action<TSourc, TTarget>>(Expression.Block(binaryExpressions), new System.Linq.Expressions.ParameterExpression[] { pe_Sourc, pe_Target });
            return lambda.Compile();
        }

        /// <summary>
        /// 高效的对象深拷贝
        /// </summary>
        /// <typeparam name="TSourc"></typeparam>
        /// <typeparam name="TTarget"></typeparam>
        /// <returns></returns>
        public static Action<TSourc, TTarget> CopyClass<TSourc, TTarget>()
        {
            System.Linq.Expressions.ParameterExpression pe_Sourc = System.Linq.Expressions.Expression.Parameter(typeof(TSourc), "p");
            System.Linq.Expressions.ParameterExpression pe_Target = System.Linq.Expressions.Expression.Parameter(typeof(TSourc), "t");
            List<System.Linq.Expressions.BinaryExpression> binaryExpressions = new List<System.Linq.Expressions.BinaryExpression>();
            foreach (var item in typeof(TSourc).GetProperties())
            {
                if (!item.CanWrite) continue;
                System.Linq.Expressions.MemberExpression property_Sourc = System.Linq.Expressions.Expression.Property(pe_Sourc, typeof(TSourc).GetProperty(item.Name));
                System.Linq.Expressions.MemberExpression property_Target = System.Linq.Expressions.Expression.Property(pe_Target, typeof(TSourc).GetProperty(item.Name));
                binaryExpressions.Add(System.Linq.Expressions.Expression.MakeBinary(ExpressionType.Assign, property_Target, property_Sourc));
            }
            System.Linq.Expressions.Expression<Action<TSourc, TTarget>> lambda = System.Linq.Expressions.Expression.Lambda<Action<TSourc, TTarget>>(Expression.Block(binaryExpressions), new System.Linq.Expressions.ParameterExpression[] { pe_Sourc, pe_Target });
            return lambda.Compile();
        }

        public static IEnumerable<T> CopyList<T>(IEnumerable<T> sourcs) where T : class  
        {
            List<T> list = new List<T>();             
            foreach (var item in sourcs)
            {
                T target = Activator.CreateInstance(typeof(T)) as T;
                UpdateValue<T>(item, target);
                list.Add(target);              
            }
            return list;
        }

        /// <summary>
        /// 对象赋值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sourc">源</param>
        /// <param name="target">目标</param>
        /// <returns></returns>
        public static void UpdateValue<T>(this T sourc, T target)
        {
            var objProper = target.GetType().GetProperties();
            foreach (var item in sourc.GetType().GetProperties())
            {
                objProper.Where(x => x.Name == item.Name).FirstOrDefault().SetValue(target, item.GetValue(sourc, null));
            }
        }



        /// <summary>
        /// 判断修改被参数
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="t">修改后对象</param>
        /// <param name="obj">修改前对象</param>
        /// <returns></returns>
        public static StringBuilder ContrastObject<T>(this T t, T obj)
        {
            StringBuilder stringBuilder = new StringBuilder();
            var objProper = obj.GetType().GetProperties();
            foreach (var item in t.GetType().GetProperties())
            {
                PropertyInfo op = objProper.Where(x => x.Name == item.Name).FirstOrDefault();
                if (op != null)
                {
                    if (op.GetCustomAttribute<DescriptionAttribute>() == null || op.GetCustomAttribute<DescriptionAttribute>().Description == "MES密码" || op.GetCustomAttribute<DescriptionAttribute>().Description == "密码")
                    {
                        continue;
                    }
                    if (item.PropertyType.BaseType.Name == "Collection`1" || item.PropertyType.BaseType.Name == "Enum")
                    {
                        if ((item.GetValue(t).ToString()) != (op.GetValue(obj).ToString()))
                        {
                            stringBuilder.AppendLine($"项目：{op.GetCustomAttribute<DescriptionAttribute>().Description}==原值：{item.GetValue(t)} --> 更改后：{op.GetValue(obj)}");
                        }
                        continue;
                    }
                    switch (item.PropertyType.Name)
                    {
                        case "Boolean":
                            if ((item.GetValue(t) as bool?) != (op.GetValue(obj) as bool?))
                            {
                                stringBuilder.AppendLine($"项目：{op.GetCustomAttribute<DescriptionAttribute>().Description}==原值：{item.GetValue(t)} --> 更改后：{op.GetValue(obj)}");
                            }
                            break;
                        case "Byte":
                            if ((item.GetValue(t) as byte?) != (op.GetValue(obj) as byte?))
                            {
                                stringBuilder.AppendLine($"项目：{op.GetCustomAttribute<DescriptionAttribute>().Description}==原值：{item.GetValue(t)} --> 更改后：{op.GetValue(obj)}");
                            }
                            break;
                        case "Int32":
                            if ((item.GetValue(t) as int?) != (op.GetValue(obj) as int?))
                            {
                                stringBuilder.AppendLine($"项目：{op.GetCustomAttribute<DescriptionAttribute>().Description}==原值：{item.GetValue(t)} --> 更改后：{op.GetValue(obj)}");
                            }
                            break;
                        case "Int16":
                            if ((item.GetValue(t) as short?) != (op.GetValue(obj) as short?))
                            {
                                stringBuilder.AppendLine($"项目：{op.GetCustomAttribute<DescriptionAttribute>().Description}==原值：{item.GetValue(t)} --> 更改后：{op.GetValue(obj)}");
                            }
                            break;
                        case "Int64":
                            if ((item.GetValue(t) as long?) != (op.GetValue(obj) as long?))
                            {
                                stringBuilder.AppendLine($"项目：{op.GetCustomAttribute<DescriptionAttribute>().Description}==原值：{item.GetValue(t)} --> 更改后：{op.GetValue(obj)}");
                            }
                            break;
                        case "Single":
                            if ((item.GetValue(t) as float?) != (op.GetValue(obj) as float?))
                            {
                                stringBuilder.AppendLine($"项目：{op.GetCustomAttribute<DescriptionAttribute>().Description}==原值：{item.GetValue(t)} --> 更改后：{op.GetValue(obj)}");
                            }
                            break;
                        case "Double":
                            if ((item.GetValue(t) as double?) != (op.GetValue(obj) as double?))
                            {
                                stringBuilder.AppendLine($"项目：{op.GetCustomAttribute<DescriptionAttribute>().Description}==原值：{item.GetValue(obj)} --> 更改后：{op.GetValue(t)}");
                            }
                            break;
                        case "String":
                            if ((item.GetValue(t) as string) != (op.GetValue(obj) as string))
                            {
                                stringBuilder.AppendLine($"项目：{op.GetCustomAttribute<DescriptionAttribute>().Description}==原值：{item.GetValue(t)} --> 更改后：{op.GetValue(obj)}");
                            }
                            break;
                        case "Decimal":
                            if ((item.GetValue(t) as decimal?) != (op.GetValue(obj) as decimal?))
                            {
                                stringBuilder.AppendLine($"项目：{op.GetCustomAttribute<DescriptionAttribute>().Description}==原值：{item.GetValue(t)} --> 更改后：{op.GetValue(obj)}");
                            }
                            break;
                    }
                }
            }
            return stringBuilder;
        }
    }
}
